package nginx

import (
	"strconv"
	"strings"
	"sync"
	"time"

	"gitee.com/xdevops/nginx-exporter/services/parsers"
	"github.com/micro-plat/lib4go/logger"
	"github.com/prometheus/client_golang/prometheus"
)

// NginxCollector 定义了一个用于收集Nginx日志数据的结构体
type NginxCollector struct {
	urlRequestCount    *prometheus.CounterVec
	urlRequestDuration *prometheus.HistogramVec
	urlStatusCodeCount *prometheus.CounterVec
	log                logger.ILogger
	mu                 sync.Mutex // 用于保护文件读取的并发访问
	durationHours      int
	parser             *parsers.Parse
}

// NewNginxCollector 创建一个新的NginxCollector实例
func NewNginxCollector(durationHours int, allowHosts ...string) *NginxCollector {
	urlRequestCount := prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: "nginx_requests_total",
			Help: "每个URL的请求总数",
		},
		[]string{"host", "url"},
	)
	urlRequestDuration := prometheus.NewHistogramVec(
		prometheus.HistogramOpts{
			Name: "nginx_request_duration_seconds",
			Help: "每个URL的请求时长（秒）",
		},
		[]string{"host", "url"},
	)
	urlStatusCodeCount := prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: "nginx_status_codes_total",
			Help: "每个URL的状态码计数",
		},
		[]string{"host", "url", "status_code"},
	)
	nc := &NginxCollector{
		urlRequestCount:    urlRequestCount,
		urlRequestDuration: urlRequestDuration,
		urlStatusCodeCount: urlStatusCodeCount,
		parser:             parsers.NewParse(allowHosts...),

		durationHours: durationHours,
		log:           logger.New("nginx-exporter"),
	}
	go nc.startReset()
	return nc

}

func (c *NginxCollector) Collectors() []prometheus.Collector {
	return []prometheus.Collector{

		c.urlRequestCount,
		c.urlRequestDuration,
		c.urlStatusCodeCount}
}

// Collect 收集指标
func (c *NginxCollector) Collect(lineChan <-chan string) {
	go func() {
		for {
			select {
			case line, ok := <-lineChan:
				if !ok {
					return
				}
				entry, err := c.parser.ParseLog(strings.TrimSpace(line))
				if err != nil {
					c.log.Error(err)
					continue
				}
				c.setEntry(entry)

			}
		}

	}()
}
func (c *NginxCollector) startReset() {
	c.log.Infof("间隔%d小时重置一次计数器", c.durationHours)
	duration := time.Duration(c.durationHours) * time.Hour //按指定的时间间隔重置
	if c.durationHours == 24 {                             // 24小时则每天凌晨重置
		now := time.Now()
		nextMidnight := time.Date(now.Year(), now.Month(), now.Day()+1, 0, 0, 0, 0, now.Location())
		duration = nextMidnight.Sub(now)
	}
	timer := time.NewTimer(duration)
	for range timer.C {
		c.reset()
		timer.Reset(time.Duration(c.durationHours) * time.Hour) // 重置为下一个时间
		c.log.Infof("重置计数器完成，下次执行%dh后", c.durationHours)
	}
}
func (c *NginxCollector) reset() {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.urlRequestCount.Reset()
	c.urlRequestDuration.Reset()
	c.urlStatusCodeCount.Reset()
}
func (c *NginxCollector) setEntry(entry parsers.LogEntry) {
	if entry.Host == "" {
		return
	}
	c.mu.Lock()
	defer c.mu.Unlock()
	c.urlRequestCount.WithLabelValues(entry.Host, entry.RemoteAddr).Inc()
	c.urlRequestDuration.WithLabelValues(entry.Host, entry.RemoteAddr).Observe(entry.RequestTime)
	if entry.IsErrorStatus {
		c.urlStatusCodeCount.WithLabelValues(entry.Host, entry.RemoteAddr, strconv.Itoa(entry.Status)).Inc()
	}

}
